﻿// <copyright file="RangeAreaVisual.cs" company="Oleg V. Polikarpotchkin">
// Copyright © 2008-2009 Oleg V. Polikarpotchkin. All Right Reserved
// </copyright>
// <author>Oleg V. Polikarpotchkin</author>
// <email>ov-p@yandex.ru</email>
// <date>2009-05-26</date>
// <summary>OpenWPFChart library. RangeAreaVisual paints the area between two Curves.</summary>
// <revision>$Id$</revision>

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Windows;
using System.Windows.Media;

namespace OpenWPFChart.Parts
{
	/// <summary>
	/// <see cref="RangeAreaVisual"/> paints the area between two Curves.
	/// </summary>
	public class RangeAreaVisual : ItemVisual
	{
		/// <summary>
		/// Renders the RangeArea
		/// </summary>
		protected internal override void Render()
		{
			Children.Clear();

			using (DrawingContext dc = RenderOpen())
			{
				RangeAreaDataView rangeAreaView = DataView as RangeAreaDataView;
				if (rangeAreaView == null)
					return;
				ItemDataView itemDataView1 = rangeAreaView.ItemDataView1
					, itemDataView2 = rangeAreaView.ItemDataView2;
				if (itemDataView1 == null || itemDataView2 == null)
					return;
				// Create visuals.
				ICurveVisual visual1 = CreateMappedCurveVisual(itemDataView1) as ICurveVisual,
					visual2 = CreateMappedCurveVisual(itemDataView2) as ICurveVisual;
				if (visual1 == null || visual2 == null)
					return;
				// Get Curve PathFigures.
				CurvePath curvePath1 = visual1.GetCurvePath(false);
				CurvePath curvePath2 = visual2.GetCurvePath(false);
				if (curvePath1.Path == null || curvePath2.Path == null)
					return;

				// Compose figures into the closed path.
				List<PathSegment> segments = new List<PathSegment>(curvePath1.Path);
				segments.Add(new LineSegment(curvePath2.Stop, false));
				segments.AddRange(curvePath2.Path);
				PathFigure figure = new PathFigure(curvePath1.Start, segments.ToArray(), true);

				// Fill the RangeArea.
				PathGeometry geometry = new PathGeometry(new PathFigure[] { figure });
				geometry.Freeze();
				dc.DrawGeometry(rangeAreaView.AreaBrush, null, geometry);
			}
		}

		static ItemVisual CreateMappedCurveVisual(ItemDataView itemDataView)
		{
			Type visualType = itemDataView.VisualCue as Type;
			if (visualType != null)
			{
				if (visualType.GetInterface("ICurveVisual") == null)
					return null;
			}
			else if (itemDataView.VisualCue is IEnumerable)
			{
				foreach (object item in itemDataView.VisualCue as IEnumerable)
				{
					visualType = item as Type;
					if (visualType != null)
					{
						if (visualType.GetInterface("ICurveVisual") != null)
							break;
					}
				}
			}

			// Create the Visual.
			ConstructorInfo ci = visualType.GetConstructor(new Type[0]);
			if (ci == null)
				return null;
			ItemVisual visual = ci.Invoke(null) as ItemVisual;
			if (visual == null)
				return null;
			visual.DataView = itemDataView;
			return visual;
		}
	}
}
